#include "UDPServer.h"
#include "Util.hpp"
#include "foreach.h"

#include <iostream>

UDPServer::UDPServer(int Port)
:ID(0)
,mPort(Port)
,mSocket(mIOService, udp::endpoint(udp::v4(),Port))
{
    //ctor
}

UDPServer::~UDPServer()
{
    //dtor
}

bool UDPServer::Start()
{
    try
    {
        boost::thread trd(boost::bind( &UDPServer::MainThread, this ));
    }
    catch (std::logic_error const& le)
    {
        std::cout << "STD::LOGIC_ERROR: " << le.what() << std::endl;
    }
    catch (boost::exception &e)
    {
        std::cout << "UDPServer::Start::BOOST_ERROR: " << ((std::string)boost::diagnostic_information(e)).c_str() << std::endl;
    }
    catch (...)
    {
        std::cout<<"UNKNOWN_ERROR"<<std::endl;
    }

    return true;
}

void UDPServer::MainThread()
{
    try
    {
        DoAccept();
        mIOService.run();
    }
    catch (std::logic_error const& le)
    {
        std::cout << "STD::LOGIC_ERROR: " << le.what() << std::endl;
    }
    catch (boost::exception &e)
    {
        std::cout << "UDPServer::MainThread::BOOST_ERROR: " << ((std::string)boost::diagnostic_information(e)).c_str() << std::endl;
    }
    catch (...)
    {
        std::cout<<"UNKNOWN_ERROR"<<std::endl;
    }
}

void UDPServer::DoAccept()
{
    try
    {
        mSocket.async_receive_from(boost::asio::buffer(mBuffer),mEndPoint,
                    boost::bind(&UDPServer::OnAccept, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
    }
    catch (std::logic_error const& le)
    {
        std::cout << "STD::LOGIC_ERROR: " << le.what() << std::endl;
    }
    catch (boost::exception &e)
    {
        std::cout << "UDPServer::DoAccept::BOOST_ERROR: " << ((std::string)boost::diagnostic_information(e)).c_str() << std::endl;
    }
    catch (...)
    {
        std::cout<<"UNKNOWN_ERROR"<<std::endl;
    }

}

void UDPServer::OnAccept(const boost::system::error_code& error, size_t bytes_transefered)
{
    if (!error)
    {
        Session *session = NULL;
        try
        {
            Session *session = NULL;
            for(int x = 0; x< mSessions.size(); ++x)
            {
                if(*mSessions[x]->GetEndPoint()==mEndPoint)
                {

                    session = mSessions[x];
                    std::cout<<"-----------Find Session------------"<<x<<std::endl;
                    break;
                }
            }
            if(session == NULL)
            {

                mSessions.push_back(new Session(ID));
                session = mSessions[ID];
                //std::list<EventListener*>::iterator iter;
                //for (iter=mListeners.begin();iter!=mListeners.end();iter++)
                //std::cout<<mBuffer.data();
                //char[bytes_transefered] data = *mBuffer.data();
                session->GetBuffer().assign(mBuffer.data());
                session->SetBytesSize(bytes_transefered);
                session->SetEndPoint(mEndPoint);

                EventListener* ev;
                std::cout<<"==============NEWSession=============\n";
                std::cout<<"OnConnect Session\n";

                foreach(ev, mListeners)
                {
                    ev->OnConnect(session);
                }
                ++ID;

                //clients.push_back(new udp::endpoint(remote_endpoint));
            }
            else
            {
                session->GetBuffer().assign(mBuffer.data());
                session->SetBytesSize(bytes_transefered);
                //session->SetEndPoint(mEndPoint);
                EventListener* ev;
                foreach(ev, mListeners)
                {
                    ev->OnReceive(session);
                }
                //std::cout<<mBuffer.data()<<std::endl<<std::endl<<std::endl;
            }
            /*for(int x = 0; x< mBuffer.size(); ++x)
            {
                mBuffer[x] = '\0';
            }*/



            DoAccept();
        }
        catch (std::logic_error const& le)
        {
            EventListener* ev;
            foreach(ev, mListeners)
            {
                ev->OnDisconnet(session);
            }
            std::cout << "STD::LOGIC_ERROR: " << le.what() << std::endl;
        }
        catch (boost::exception &e)
        {
            EventListener* ev;
            foreach(ev, mListeners)
            {
                ev->OnDisconnet(session);
            }
            std::cout << "UDPServer::OnAccept::BOOST_ERROR: " << ((std::string)boost::diagnostic_information(e)).c_str() << std::endl;
        }
        catch (...)
        {
            EventListener* ev;
            foreach(ev, mListeners)
            {
                ev->OnDisconnet(session);
            }
            std::cout<<"UNKNOWN_ERROR"<<std::endl;
        }
    }

    if (error == boost::asio::error::eof)
    {
        std::cout<<"EOF"<<std::endl;
    }

}

void UDPServer::Send(const boost::array<char*, 1>& SendBuffer,std::size_t bytes_transferred, Session* session)
{
    try
    {
        if(session->GetActive())
        {
            mSocket.send_to(boost::asio::buffer(SendBuffer,bytes_transferred), *session->GetEndPoint());
        }
    }
    catch (std::logic_error const& le)
    {
        std::cout << "STD::LOGIC_ERROR: " << le.what() << std::endl;
    }
    catch (boost::exception &e)
    {
        std::cout << "UDPServer::Send::BOOST_ERROR: " << ((std::string)boost::diagnostic_information(e)).c_str() << std::endl;
        std::list<EventListener*>::iterator iter = mListeners.begin();
        for (;iter!=mListeners.end();iter++)
        {
            (*iter)->OnDisconnet(session);
        }
    }
    catch (...)
    {
        std::cout<<"UNKNOWN_ERROR"<<std::endl;
    }
}
void UDPServer::Send(const char* SendBuffer,std::size_t bytes_transferred, Session* session)
{
    try
    {
        if(session->GetActive())
        {
            mSocket.send_to(boost::asio::buffer(SendBuffer,bytes_transferred), *session->GetEndPoint());
        }
    }
    catch (std::logic_error const& le)
    {
        std::cout << "STD::LOGIC_ERROR: " << le.what() << std::endl;
    }
    catch (boost::exception &e)
    {
        std::cout << "UDPServer::Send::BOOST_ERROR: " << ((std::string)boost::diagnostic_information(e)).c_str() << std::endl;
        std::list<EventListener*>::iterator iter = mListeners.begin();
        for (;iter!=mListeners.end();iter++)
        {
            (*iter)->OnDisconnet(session);
        }
    }
    catch (...)
    {
        std::cout<<"UNKNOWN_ERROR"<<std::endl;
    }
}
void UDPServer::Send(const boost::array<char, 1024>& SendBuffer,std::size_t bytes_transferred, Session* session)
{
    try
    {
        if(session->GetActive())
        {
            mSocket.send_to(boost::asio::buffer(SendBuffer,bytes_transferred), *session->GetEndPoint());
        }
    }
    catch (std::logic_error const& le)
    {
        std::cout << "STD::LOGIC_ERROR: " << le.what() << std::endl;
    }
    catch (boost::exception &e)
    {
        std::cout << "UDPServer::Send::BOOST_ERROR: " << ((std::string)boost::diagnostic_information(e)).c_str() << std::endl;
        std::list<EventListener*>::iterator iter = mListeners.begin();
        for (;iter!=mListeners.end();iter++)
        {
            (*iter)->OnDisconnet(session);
        }
    }
    catch (...)
    {
        std::cout<<"UNKNOWN_ERROR"<<std::endl;
    }
}
void UDPServer::Error(const boost::system::error_code& error)
{
    if (error)
    {
        throw std::logic_error("ERRO AQUI!!");
    }
}

/// Adiciona um observador
void UDPServer::AddListener(EventListener* listener)
{
    mListeners.push_back(listener);
}

/// Retorna a lista de sockets
udp::socket* UDPServer::GetSocket()
{
    return &mSocket;
}
udp::endpoint* UDPServer::GetEndPoint(int ID)
{
    return mSessions[ID]->GetEndPoint();
}
std::deque<Session*> UDPServer::GetSessionList()
{
   return mSessions;
}
